Skip to main content

Filtering a periodic noise

Note the dithering in the image below

Download original notebook
(*VB[*)(FrontEndRef["42d99f3c-deb2-402c-ac07-1b664f611765"])(*,*)(*"1:eJxTTMoPSmNkYGAoZgESHvk5KRCeEJBwK8rPK3HNS3GtSE0uLUlMykkNVgEKmxilWFqmGSfrpqQmGemaGBgl6yYmG5jrGiaZmZmkmRkampuZAgCIexVv"*)(*]VB*)

We can use 2D Fourier transformation and filtern it out in the frequency space. Firstly, lets convert an image to normal array.

donald = ImageData[
  ColorSeparate[(*VB[*)(FrontEndRef["42d99f3c-deb2-402c-ac07-1b664f611765"])(*,*)(*"1:eJxTTMoPSmNkYGAoZgESHvk5KRCeEJBwK8rPK3HNS3GtSE0uLUlMykkNVgEKmxilWFqmGSfrpqQmGemaGBgl6yYmG5jrGiaZmZmkmRkampuZAgCIexVv"*)(*]VB*), "L"]
, "Real32"];

Helper functions

It implements a symmetric 2D fourier transformation and its inverse version

fourier2d[data_] := Module[{d, fw, nRow, nCol},
  {nRow, nCol} = Dimensions[data];
  d = data;
  d = d (*SpB[*)Power[(-1)(*|*),(*|*)Table[i + j, {i, nRow}, {j, nCol}]](*]SpB*);
  fw = Fourier[d, FourierParameters -> {1, 1}];
  
  {Log[1 + Abs@fw], Arg[fw]}
]

ifourier2d[amp_, phase_] := Module[{d, nRow, nCol},
  {nRow, nCol} = Dimensions[amp];
  
  d = (Exp[amp] - 1.0) Exp[I phase];
  
  InverseFourier[d, FourierParameters -> {1, 1}] // Abs
]

preview[data_, opts___] := With[{a = data},
  Image[a / Max[a], "Real32", opts]
]

Filtering in frequency domain

Decompose an image to an amplitude and phase using 2D fourier transformation

{amp, phase} = fourier2d[donald];

Row[preview /@ {amp, phase}]
(*GB[*){{(*VB[*)(FrontEndRef["ae7ff7bc-fbe0-48f9-b002-34692c9a02f1"])(*,*)(*"1:eJxTTMoPSmNkYGAoZgESHvk5KRCeEJBwK8rPK3HNS3GtSE0uLUlMykkNVgEKJ6aap6WZJyXrpiWlGuiaWKRZ6iYZGBjpGpuYWRolWyYaGKUZAgCYoxYC"*)(*]VB*)(*|*),(*|*)(*VB[*)(FrontEndRef["52b0789a-ced5-400f-a2fb-3f83841a7aef"])(*,*)(*"1:eJxTTMoPSmNkYGAoZgESHvk5KRCeEJBwK8rPK3HNS3GtSE0uLUlMykkNVgEKmxolGZhbWCbqJqemmOqaGBik6SYapSXpGqdZGFuYGCaaJ6amAQCFtBYA"*)(*]VB*)}}(*]GB*)

Filter an amplidute spectrum

EventHandler[InputRaster[preview[amp]], (masked = #)&]
(*VB[*)(EventObject[<|"Id" -> "10b52017-f695-4ab4-9978-91d2d0544679", "View" -> "a25c2ee4-9038-4b3f-8b3b-27e4fd68ff56"|>])(*,*)(*"1:eJxTTMoPSmNkYGAoZgESHvk5KRCeEJBwK8rPK3HNS3GtSE0uLUlMykkNVgEKJxqZJhulpproWhoYW+iaJBmn6VokGSfpGpmnmqSlmFmkpZmaAQCGtBXh"*)(*]VB*)

Here is an example how it can be masked

masked // preview 
(*VB[*)(FrontEndRef["f46a0e1d-ec19-4d28-954f-4155aaecbb8a"])(*,*)(*"1:eJxTTMoPSmNkYGAoZgESHvk5KRCeEJBwK8rPK3HNS3GtSE0uLUlMykkNVgEKp5mYJRqkGqbopiYbWuqapBhZ6FqamqTpmhiamiYmpiYnJVkkAgCKWhYw"*)(*]VB*)

Take masked amplitude and recombine it with phase to get back a normal image

ifourier2d @@ {With[{max = Max[amp]},
  ImageData[masked, "Real32"][[All,All,1]] max 
], phase};

Grid[{
  {preview[donald, Magnification->2], preview[%, Magnification->2]},
  {"Original", "Filtered"}
}]
(*GB[*){{(*VB[*)(FrontEndRef["913b0b2f-1c22-4509-80c8-b61a22b3ea86"])(*,*)(*"1:eJxTTMoPSmNkYGAoZgESHvk5KRCeEJBwK8rPK3HNS3GtSE0uLUlMykkNVgEKWxoaJxkkGaXpGiYbGemamBpY6loYJFvoJpkZJhoZJRmnJlqYAQB5EhUw"*)(*]VB*)(*|*),(*|*)(*VB[*)(FrontEndRef["cee750d0-43e2-4c88-9f00-17884b94bfd1"])(*,*)(*"1:eJxTTMoPSmNkYGAoZgESHvk5KRCeEJBwK8rPK3HNS3GtSE0uLUlMykkNVgEKJ6emmpsapBjomhinGumaJFtY6FqmGRjoGppbWJgkWZokpaUYAgCDmxV8"*)(*]VB*)}(*||*),(*||*){"Original"(*|*),(*|*)"Filtered"}}(*]GB*)